package demo.xml.jaxen.custom;

import java.util.Iterator;

import org.jaxen.DefaultNavigator;
import org.jaxen.FunctionCallException;
import org.jaxen.JaxenConstants;
import org.jaxen.NamedAccessNavigator;
import org.jaxen.Navigator;
import org.jaxen.UnsupportedAxisException;
import org.jaxen.XPath;
import org.jaxen.pattern.Pattern;
import org.jaxen.saxpath.SAXPathException;
import org.jaxen.util.AncestorAxisIterator;
import org.jaxen.util.AncestorOrSelfAxisIterator;
import org.jaxen.util.DescendantAxisIterator;
import org.jaxen.util.DescendantOrSelfAxisIterator;
import org.jaxen.util.FollowingAxisIterator;
import org.jaxen.util.FollowingSiblingAxisIterator;
import org.jaxen.util.PrecedingAxisIterator;
import org.jaxen.util.PrecedingSiblingAxisIterator;
import org.jaxen.util.SelfAxisIterator;

import com.titan.core.utils.data.AssertUtils;
import com.titan.core.utils.data.JaxenUtils;
import com.titan.core.utils.io.ConsoleUtils;

//  implements Navigator
// public class CustomNavigator extends DefaultNavigator implements NamedAccessNavigator {
public class CustomNavigator implements Navigator, NamedAccessNavigator {
    private static final long serialVersionUID = 1L;
    private volatile static Navigator instance = null;

    public static Navigator getInstance() {
        if (instance == null) {
            synchronized (CustomNavigator.class) {
                if (instance == null) {
                    instance = new CustomNavigator();
                }
            }
        }
        return instance;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.jaxen.Navigator#getDescendantAxisIterator(java.lang.Object)
     */
    @Override
    public Iterator<?> getDescendantAxisIterator(Object contextNode) throws UnsupportedAxisException {
        return new DescendantAxisIterator(contextNode, this);
    }

    /**
     * Throws <code>UnsupportedAxisException</code>
     * 
     * @param contextNode
     * @return never returns
     * @throws UnsupportedAxisException
     */
    @Override
    public Iterator<?> getParentAxisIterator(Object contextNode) throws UnsupportedAxisException {
        JaxenUtils.print("contextNode", contextNode);
        return AssertUtils.fail("getParentAxisIterator");
//        throw new UnsupportedAxisException("parent");
    }

    @Override
    public Iterator<?> getAncestorAxisIterator(Object contextNode) throws UnsupportedAxisException {
        return new AncestorAxisIterator(contextNode, this);
    }

    @Override
    public Iterator<?> getFollowingSiblingAxisIterator(Object contextNode) throws UnsupportedAxisException {
        return new FollowingSiblingAxisIterator(contextNode, this);
    }

    @Override
    public Iterator<?> getPrecedingSiblingAxisIterator(Object contextNode) throws UnsupportedAxisException {
        return new PrecedingSiblingAxisIterator(contextNode, this);
    }

    @Override
    public Iterator<?> getFollowingAxisIterator(Object contextNode) throws UnsupportedAxisException {
        return new FollowingAxisIterator(contextNode, this);

        // throw new UnsupportedAxisException("following");
    }

    @Override
    public Iterator<?> getPrecedingAxisIterator(Object contextNode) throws UnsupportedAxisException {
        return new PrecedingAxisIterator(contextNode, this);

        // throw new UnsupportedAxisException("preceding");
    }

    @Override
    public Iterator<?> getAttributeAxisIterator(Object contextNode) throws UnsupportedAxisException {
        JaxenUtils.print("contextNode", contextNode);
        return AssertUtils.fail("getAttributeAxisIterator");
//        throw new UnsupportedAxisException("attribute");
    }

    @Override
    public Iterator<?> getNamespaceAxisIterator(Object contextNode) throws UnsupportedAxisException {
        JaxenUtils.print("contextNode", contextNode);
        return AssertUtils.fail("getNamespaceAxisIterator");
//        throw new UnsupportedAxisException("namespace");
    }

    @Override
    public Iterator<?> getSelfAxisIterator(Object contextNode) throws UnsupportedAxisException {
        return new SelfAxisIterator(contextNode);
    }

    @Override
    public Iterator<?> getDescendantOrSelfAxisIterator(Object contextNode) throws UnsupportedAxisException {
        return new DescendantOrSelfAxisIterator(contextNode, this);
    }

    @Override
    public Iterator<?> getAncestorOrSelfAxisIterator(Object contextNode) throws UnsupportedAxisException {
        return new AncestorOrSelfAxisIterator(contextNode, this);
    }

    @Override
    public short getNodeType(Object node) {
        if (isElement(node)) {
            return Pattern.ELEMENT_NODE;
        } else if (isAttribute(node)) {
            return Pattern.ATTRIBUTE_NODE;
        } else if (isText(node)) {
            return Pattern.TEXT_NODE;
        } else if (isComment(node)) {
            return Pattern.COMMENT_NODE;
        } else if (isDocument(node)) {
            return Pattern.DOCUMENT_NODE;
        } else if (isProcessingInstruction(node)) {
            return Pattern.PROCESSING_INSTRUCTION_NODE;
        } else if (isNamespace(node)) {
            return Pattern.NAMESPACE_NODE;
        } else {
            return Pattern.UNKNOWN_NODE;
        }
    }

    @Override
    public Object getParentNode(Object contextNode) throws UnsupportedAxisException {
        Iterator<?> iter = getParentAxisIterator(contextNode);
        if (iter != null && iter.hasNext()) {
            return iter.next();
        }
        return null;
    }

    @Override
    public Object getDocument(String url) throws FunctionCallException {
        ConsoleUtils.log("url", url);
        return AssertUtils.fail("getDocument");
    }

    @Override
    public Object getElementById(Object contextNode, String elementId) {
        ConsoleUtils.log("clazz", contextNode == null ? null : contextNode.getClass(), "contextNode", contextNode);
        ConsoleUtils.log("elementId", elementId);
        return AssertUtils.fail("translateNamespacePrefixToUri");
    }

    @Override
    public Object getDocumentNode(Object contextNode) {
        ConsoleUtils.log("clazz", contextNode == null ? null : contextNode.getClass(), "contextNode", contextNode);
        return AssertUtils.fail("getDocumentNode");
    }

    @Override
    public String translateNamespacePrefixToUri(String prefix, Object element) {
        ConsoleUtils.log("prefix", prefix, "clazz", element == null ? null : element.getClass(), "element", element);
        return AssertUtils.fail("translateNamespacePrefixToUri");
    }

    @Override
    public String getProcessingInstructionTarget(Object obj) {
        ConsoleUtils.log("clazz", obj == null ? null : obj.getClass(), "obj", obj);
        return AssertUtils.fail("getProcessingInstructionTarget");
    }

    @Override
    public String getProcessingInstructionData(Object obj) {
        ConsoleUtils.log("clazz", obj == null ? null : obj.getClass(), "obj", obj);
        return AssertUtils.fail("getProcessingInstructionData");
    }

    @Override
    public String getElementNamespaceUri(Object element) {
        ConsoleUtils.log("clazz", element == null ? null : element.getClass(), "element", element);
        return AssertUtils.fail("getElementNamespaceUri");
    }

    @Override
    public String getElementName(Object element) {
        ConsoleUtils.log("clazz", element == null ? null : element.getClass(), "element", element);
        AssertUtils.fail("getElementName");
        return null;
    }

    @Override
    public String getElementQName(Object element) {
        ConsoleUtils.log("clazz", element == null ? null : element.getClass(), "element", element);
        AssertUtils.fail("getElementQName");
        return null;
    }

    @Override
    public String getAttributeNamespaceUri(Object attr) {
        ConsoleUtils.log("clazz", attr == null ? null : attr.getClass(), "attr", attr);
        AssertUtils.fail("getAttributeNamespaceUri");
        return null;
    }

    @Override
    public String getAttributeName(Object attr) {
        ConsoleUtils.log("clazz", attr == null ? null : attr.getClass(), "attr", attr);
        AssertUtils.fail("getAttributeName");
        return null;
    }

    @Override
    public String getAttributeQName(Object attr) {
        ConsoleUtils.log("clazz", attr == null ? null : attr.getClass(), "attr", attr);
        AssertUtils.fail("getAttributeQName");
        return null;
    }

    @Override
    public boolean isDocument(Object object) {
        ConsoleUtils.log("clazz", object == null ? null : object.getClass(), "object", object);
        AssertUtils.fail("isDocument");
        return false;
    }

    @Override
    public boolean isElement(Object object) {
        ConsoleUtils.log("clazz", object == null ? null : object.getClass(), "object", object);
        AssertUtils.fail("isElement");
        return false;
    }

    @Override
    public boolean isAttribute(Object object) {
        ConsoleUtils.log("clazz", object == null ? null : object.getClass(), "object", object);
        AssertUtils.fail("isAttribute");
        return false;
    }

    @Override
    public boolean isNamespace(Object object) {
        ConsoleUtils.log("clazz", object == null ? null : object.getClass(), "object", object);
        AssertUtils.fail("isNamespace");
        return false;
    }

    @Override
    public boolean isComment(Object object) {
        ConsoleUtils.log("clazz", object == null ? null : object.getClass(), "object", object);
        AssertUtils.fail("isComment");
        return false;
    }

    @Override
    public boolean isText(Object object) {
        ConsoleUtils.log("clazz", object == null ? null : object.getClass(), "object", object);
        AssertUtils.fail("isText");
        return false;
    }

    @Override
    public boolean isProcessingInstruction(Object object) {
        ConsoleUtils.log("clazz", object == null ? null : object.getClass(), "object", object);
        AssertUtils.fail("isProcessingInstruction");
        return false;
    }

    @Override
    public String getCommentStringValue(Object comment) {
        ConsoleUtils.log("clazz", comment == null ? null : comment.getClass(), "comment", comment);
        AssertUtils.fail("getCommentStringValue");
        return null;
    }

    @Override
    public String getElementStringValue(Object element) {
        ConsoleUtils.log("clazz", element == null ? null : element.getClass(), "element", element);
        AssertUtils.fail("getElementStringValue");
        return null;
    }

    @Override
    public String getAttributeStringValue(Object attr) {
        ConsoleUtils.log("clazz", attr == null ? null : attr.getClass(), "attr", attr);
        AssertUtils.fail("getAttributeStringValue");
        return null;
    }

    @Override
    public String getNamespaceStringValue(Object ns) {
        ConsoleUtils.log("clazz", ns == null ? null : ns.getClass(), "ns", ns);
        AssertUtils.fail("getNamespaceStringValue");
        return null;
    }

    @Override
    public String getTextStringValue(Object text) {
        ConsoleUtils.log("clazz", text == null ? null : text.getClass(), "text", text);
        AssertUtils.fail("getTextStringValue");
        return null;
    }

    @Override
    public String getNamespacePrefix(Object ns) {
        ConsoleUtils.log("clazz", ns == null ? null : ns.getClass(), "ns", ns);
        AssertUtils.fail("getNamespacePrefix");
        return null;
    }

    @Override
    public XPath parseXPath(String xpath) throws SAXPathException {
        ConsoleUtils.log("xpath", xpath);
        AssertUtils.fail("parseXPath");
        return null;
    }

    @Override
    public Iterator<?> getChildAxisIterator(Object contextNode) throws UnsupportedAxisException {
        JaxenUtils.print("contextNode", contextNode);
        return AssertUtils.fail("getChildAxisIterator");
//        return JaxenConstants.EMPTY_ITERATOR;
    }

    @Override
    public Iterator<?> getChildAxisIterator(Object contextNode, String localName, String namespacePrefix, String namespaceURI) throws UnsupportedAxisException {
        JaxenUtils.print("contextNode", contextNode);
        ConsoleUtils.log("localName", localName, "namespacePrefix", namespacePrefix, "namespaceURI", namespaceURI);
        AssertUtils.fail("getChildAxisIterator");

        return JaxenConstants.EMPTY_ITERATOR;
    }

    @Override
    public Iterator<?> getAttributeAxisIterator(Object contextNode, String localName, String namespacePrefix, String namespaceURI) throws UnsupportedAxisException {
        JaxenUtils.print("contextNode", contextNode);
        ConsoleUtils.log("localName", localName, "namespacePrefix", namespacePrefix, "namespaceURI", namespaceURI);
        AssertUtils.fail("getAttributeAxisIterator");
        return null;
    }

}
